﻿using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

using zijian666.Core;
using zijian666.Core.Abstractions;

namespace zijian666.Http;

/// <summary>
/// <seealso cref="HttpClient"/> 扩展方法
/// </summary>
public static class HttpClientBodyExtensions
{
    /// <summary>
    /// 解析序列化协议
    /// </summary>
    private static string ParseProtocol(MediaTypeHeaderValue header)
    {
        var media = header?.MediaType;
        if (media is null)
        {
            return "";
        }
        var index = media.LastIndexOf('/');
        if (index < 0)
        {
            return media;
        }
        return media.Substring(index + 1);
    }

    /// <summary>
    /// 获取指定协议的序列化组件
    /// </summary>
    /// <param name="protocol"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException">没有找到可以解析 <paramref name="protocol"/> 的组件</exception>
    private static IStringSerializer GetSerializer(string protocol)
    {
        return FeatureManager.Get<IStringSerializer>(x => string.Equals(x.Protocol, protocol, StringComparison.OrdinalIgnoreCase))
            ?? throw new NotImplementedException("没有找到可以解析 " + protocol + "的组件");
    }


    /// <summary>
    /// 通过json序列化协议序列化data, 并设置请求的请求体
    /// </summary>
    public static FluentHttpClient JsonBody(this FluentHttpClient fluent, object data)
    {
        var json = (data is null ? null : GetSerializer("json").ToString(data)) ?? "null";
        return Body(fluent, "application/json;charset=utf-8", json);
    }

    /// <summary>
    /// 通过序列化协议序列化data, 并设置请求的请求体
    /// </summary>
    public static FluentHttpClient Body(this FluentHttpClient fluent, string contentType, object data)
    {
        if (data is byte[] b)
        {
            return fluent.Body(contentType, b);
        }
        var type = MediaTypeHeaderValue.Parse(contentType);
        if (data is string s)
        {
            return fluent.Body(type, s);
        }
        var protocol = ParseProtocol(type);
        var serializer = GetSerializer(protocol);
        var str = serializer.ToString(data) ?? "";
        return fluent.Body(type, str);
    }
    /// <summary>
    /// 异步发送请求, 获取返回值, 通过序列化协议转换对象
    /// </summary>
    public static async Task<T> ReadAsObejctAsync<T>(this Task<HttpResponseMessage> responseTask, string dataType = "json")
    {
        var response = await responseTask;
        response = response.EnsureSuccessStatusCode();
        var protocol = dataType ?? ParseProtocol(response.Content.Headers?.ContentType);
        var serializer = GetSerializer(protocol);
        var str = await response.Content.ReadAsStringAsync();
        return (T)serializer.ToObject(str, typeof(T));
    }

    /// <summary>
    /// 发送请求, 获取返回值, 通过序列化协议转换对象
    /// </summary>
    public static T ReadAsObejct<T>(this HttpResponseMessage response, string dataType = "json")
    {
        response = response.EnsureSuccessStatusCode();
        var protocol = dataType ?? ParseProtocol(response.Content.Headers?.ContentType) ?? "json";
        var serializer = GetSerializer(protocol);
        var str = response.Content.ReadAsString();
        return (T)serializer.ToObject(str, typeof(T));
    }

    /// <summary>
    /// 异步发送请求并获取返回一个动态对象
    /// </summary>
    public static async Task<dynamic> ReadAsDynamicAsync(this Task<HttpResponseMessage> response, string dataType = "json")
    {
        var convertor = FeatureManager.GetRequired<IFormatterConverterFeature>();
        var obj = await ReadAsObejctAsync<object>(response, dataType);
        return convertor.ToDynamic(obj);
    }

    /// <summary>
    /// 发送请求并获取返回一个动态对象
    /// </summary>
    public static dynamic ReadAsDynamic(this HttpResponseMessage response, string dataType = "json")
    {
        var convertor = FeatureManager.GetRequired<IFormatterConverterFeature>();
        var obj = ReadAsObejct<object>(response, dataType);
        return convertor.ToDynamic(obj);
    }

    /// <summary>
    /// 异步将 HTTP 内容通过json协议序列化为特定对象
    /// </summary>
    public static async Task<T> ReadAsJsonObejctAsync<T>(this Task<HttpResponseMessage> response)
    {
        var serializer = GetSerializer("json");
        var json = await response.ReadAsStringAsync();
        return (T)serializer.ToObject(json, typeof(T));
    }

    /// <summary>
    /// 将 HTTP 内容通过json协议序列化为特定对象
    /// </summary>
    public static T ReadAsJsonObejct<T>(this HttpResponseMessage response)
    {
        var serializer = GetSerializer("json");
        var json = response.ReadAsString();
        return (T)serializer.ToObject(json, typeof(T));
    }


    /// <summary>
    /// 异步发送请求, 获取返回值, 通过序列化协议转换对象
    /// </summary>
    public static async Task<T> ReadAsObejctAsync<T>(this FluentHttpClient fluent, string dataType = "json", int timeoutMilliseconds = HttpClientExtensions.DEFAULT_TIMEOUT)
        => await fluent.SendAsync(timeoutMilliseconds).ReadAsObejctAsync<T>(dataType);

    /// <summary>
    /// 发送请求, 获取返回值, 通过序列化协议转换对象
    /// </summary>
    public static T ReadAsObejct<T>(this FluentHttpClient fluent, string dataType = "json", int timeoutMilliseconds = HttpClientExtensions.DEFAULT_TIMEOUT)
        => fluent.Send(timeoutMilliseconds).ReadAsObejct<T>(dataType);


    /// <summary>
    /// 异步发送请求并获取返回一个动态对象
    /// </summary>
    public static async Task<dynamic> ReadAsDynamicAsync(this FluentHttpClient fluent, string dataType = "json", int timeoutMilliseconds = HttpClientExtensions.DEFAULT_TIMEOUT)
    {
        var convertor = FeatureManager.GetRequired<IFormatterConverterFeature>();
        var obj = await ReadAsObejctAsync<object>(fluent, dataType, timeoutMilliseconds);
        return convertor.ToDynamic(obj);
    }

    /// <summary>
    /// 发送请求并获取返回一个动态对象
    /// </summary>
    public static dynamic ReadAsDynamic(this FluentHttpClient fluent, string dataType = "json", int timeoutMilliseconds = HttpClientExtensions.DEFAULT_TIMEOUT)
    {
        var convertor = FeatureManager.GetRequired<IFormatterConverterFeature>();
        var obj = ReadAsObejct<object>(fluent, dataType, timeoutMilliseconds);
        return convertor.ToDynamic(obj);
    }


    /// <summary>
    /// 异步发送请求, 获取返回值, 通过json序列化协议转换对象
    /// </summary>
    public static Task<T> ReadAsJsonObejctAsync<T>(this FluentHttpClient fluent, int timeoutMilliseconds = HttpClientExtensions.DEFAULT_TIMEOUT)
        => fluent.ReadAsObejctAsync<T>("json", timeoutMilliseconds);

    /// <summary>
    /// 异步发送请求, 获取返回值, 通过json序列化协议转换对象
    /// </summary>
    public static T ReadAsJsonObejct<T>(this FluentHttpClient fluent, int timeoutMilliseconds = HttpClientExtensions.DEFAULT_TIMEOUT)
          => fluent.ReadAsObejct<T>("json", timeoutMilliseconds);
}
